package logique.parser;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Iterator;

import logique.parser.factories.TailleVilleFactory;
import logique.reseau.Route;
import logique.reseau.Troncon;
import logique.reseau.Ville;
import logique.reseau.atouts.AtoutTouristiqueTroncon;
import logique.reseau.atouts.AtoutTouristiqueVille;
import logique.reseau.caracteristiques.Caracteristique;
import logique.reseau.caracteristiques.Peage;
import logique.reseau.caracteristiques.Radar;
import logique.reseau.classements.Classement;
import logique.reseau.tailles.TailleVille;

import org.dom4j.Element;
import org.dom4j.io.XMLWriter;
import org.dom4j.tree.BaseElement;

/**
 * 
 * @author camille
 *
 */
public class NetworkWriter {

	private Parser parser;

	public NetworkWriter(Parser parser) {
		this.parser = parser;
	}

	@SuppressWarnings("unchecked")
	public void handleVilleFileSystem(Element villeElement) throws IOException {
		
		for (Iterator i = villeElement.elementIterator(); i.hasNext();) {
			Element element = (Element) i.next();

			if (element.getName().toLowerCase().equals(Parser.NOM_NODE_NAME)) {
				XMLWriter writer = new XMLWriter(new FileWriter(parser.getVilleFile(element.getStringValue().toLowerCase())));
				writer.writeOpen(new BaseElement(Parser.DESC_NODE_NAME));
				writer.write(villeElement);
				writer.close();
				break;
			}
		}
	}

	@SuppressWarnings("unchecked")
	public void handleRouteFileSystem(Element routeElement) throws IOException {

		String routeName = null;

		for (Iterator i = routeElement.elementIterator(); i.hasNext();) {
			Element element = (Element) i.next();

			if (element.getName().toLowerCase().equals(Parser.NOM_NODE_NAME)) {
				routeName = element.getStringValue().toLowerCase();

				XMLWriter writer = new XMLWriter(new FileWriter(parser.getRouteFile(routeName)));
				writer.writeOpen(new BaseElement(Parser.DESC_NODE_NAME));
				writer.write(routeElement);
				writer.close();
				break;
			}
		}

		for (Iterator i = routeElement.elementIterator(); i.hasNext();) {
			Element element = (Element) i.next();

			if (element.getName().toLowerCase().equals(Parser.TRONCON_NODE_NAME)) {
				handleTronconFileSystem(element, routeName);
			}
		}
	}

	@SuppressWarnings("unchecked")
	private void handleTronconFileSystem(Element tronconElement, String routeName) throws IOException {
		for (Iterator i = tronconElement.elementIterator(); i.hasNext();) {
			Element element = (Element) i.next();

			if (element.getName().toLowerCase().equals(Parser.VILLE1_NODE_NAME)) {
				addTronconToFile(element.getStringValue().toLowerCase(), tronconElement, routeName);
			}

			if (element.getName().toLowerCase().equals(Parser.VILLE2_NODE_NAME)) {
				addTronconToFile(element.getStringValue().toLowerCase(), tronconElement, routeName);
			}
		}
	}

	private void addTronconToFile(String ville, Element tronconElement, String routeName) throws IOException {

		XMLWriter writer;
		File villeFile = parser.getVilleFile(ville);

		tronconElement.addAttribute(Parser.ROUTE_NODE_NAME, routeName);

		if (!villeFile.exists()) {
			writer = new XMLWriter(new FileWriter(villeFile));
			writer.writeOpen(new BaseElement(Parser.DESC_NODE_NAME));
			ecrireVilleParDefaut(ville, writer);
			writer.write(tronconElement);
			writer.close();
		}
		else {
			writer = new XMLWriter(new FileWriter(villeFile, true));
			writer.write(tronconElement);
			writer.close();
		}
	}

	public void finishAllFiles() throws IOException {

		File dir;

		// Close villes files
		dir = new File(parser.getWorkspace() + File.separator + Parser.VILLES_DIR);

		for (File vF : dir.listFiles()) {
			finishFile(vF);
		}

		// Close routes files
		dir = new File(parser.getWorkspace() + File.separator + Parser.ROUTES_DIR);

		for (File rF : dir.listFiles()) {
			finishFile(rF);
		}

		parser.segmentationDone(true);
	}

	private void finishFile(File file) throws IOException {

		BaseElement closeElement = new BaseElement(Parser.DESC_NODE_NAME);

		XMLWriter writer = new XMLWriter(new FileWriter(file, true));
		writer.writeClose(closeElement);
		writer.close();
	}

	public void addToFS(Ville ville) throws IOException {
		File villeFile = parser.getVilleFile(ville.getNom());
		XMLWriter writer = new XMLWriter(new FileWriter(villeFile));

		ecrireVille(writer, ville);
		writer.close();

		finishFile(villeFile);
	}

	public void addToFS(Route route) throws Exception {
		File routeFile = parser.getRouteFile(route.getNom());
		XMLWriter writer = new XMLWriter(new FileWriter(routeFile));

		ecrireRoute(writer, route);
		writer.close();

		finishFile(routeFile);
	}

	public void addToFS(Troncon troncon) throws Exception {
		File routeFile = parser.getRouteFile(troncon.getRoute().getNom() + Parser.TEMP_FILE_EXT);
		XMLWriter writer = new XMLWriter(new FileWriter(routeFile));

		ecrireRoute(writer, troncon.getRoute());
		ecrireTroncon(writer, troncon);
		writer.close();

		finishFile(routeFile);
	}

	public void removeFromFS(Ville ville) {
		File villeFile = parser.getVilleFile(ville.getNom());
		villeFile.delete();
	}

	public void removeFromFS(Route route) {
		File routeFile = parser.getRouteFile(route.getNom());
		routeFile.delete();
	}

	public void removeFromFS(Troncon troncon) {
		//TODO
	}
	
	public void updateFS(Ville ville, Ville newVille){
		//TODO
	}
	
	public void updateFS(Route route, Route newRoute){
		//TODO
	}
	
	public void updateFS(Troncon troncon, Troncon newTroncon){
		//TODO
	}

	public void ecrireVille(XMLWriter writer, Ville ville) throws IOException {

		BaseElement villeElement = new BaseElement(Parser.VILLE_NODE_NAME);

		writer.writeOpen(villeElement);

		ecrireNom(writer, ville.getNom());
		
		if(ville.getTaille() != null){
			ecrireTaille(writer, ville.getTaille());
		}

		for (AtoutTouristiqueVille atout : ville.getAtoutsTouristiques()) {
			ecrireATV(writer, atout);
		}

		writer.writeClose(villeElement);

		villeElement.clearContent();
	}

	private void ecrireVilleParDefaut(String name, XMLWriter writer) throws IOException {
		BaseElement villeElement = new BaseElement(Parser.VILLE_NODE_NAME);
		BaseElement nomElement = new BaseElement(Parser.NOM_NODE_NAME);
		BaseElement typeElement = new BaseElement(Parser.TYPE_NODE_NAME);
		BaseElement touristElement = new BaseElement(Parser.TOURIST_NODE_NAME);

		writer.writeOpen(villeElement);

		writer.writeOpen(nomElement);
		writer.write(name);
		writer.writeClose(nomElement);

		writer.writeOpen(typeElement);
		writer.write(TailleVilleFactory.PETITE);
		writer.writeClose(typeElement);

		writer.writeOpen(touristElement);
		writer.write(Parser.IND_NEGATIVE);
		writer.writeClose(touristElement);

		writer.writeClose(villeElement);
	}

	private void ecrireTaille(XMLWriter writer, TailleVille taille) throws IOException {
		BaseElement tailleElement = new BaseElement(Parser.TYPE_NODE_NAME);

		writer.writeOpen(tailleElement);
		writer.write(taille.toString());
		writer.writeClose(tailleElement);

		tailleElement.clearContent();
	}

	private void ecrireATV(XMLWriter writer, AtoutTouristiqueVille atout) throws IOException {
		BaseElement atoutElement = new BaseElement(Parser.TOURIST_NODE_NAME);

		writer.writeOpen(atoutElement);
		writer.write((atout != null) ? Parser.IND_POSITIVE : Parser.IND_NEGATIVE);
		writer.writeClose(atoutElement);

		atoutElement.clearContent();
	}

	public void ecrireRoute(XMLWriter writer, Route route) throws Exception {
		BaseElement routeElement = new BaseElement(Parser.ROUTE_NODE_NAME);

		writer.writeOpen(routeElement);

		ecrireNom(writer, route.getNom());
		ecrireClassement(writer, route.getClassement());

		for (Troncon troncon : parser.getControleur().getTroncons(route)) {
			ecrireTroncon(writer, troncon);
		}

		if (!parser.fullParsing()) {
			route.clearTroncons();
		}

		writer.writeClose(routeElement);

		routeElement.clearContent();
	}

	private void ecrireNom(XMLWriter writer, String nom) throws IOException {
		BaseElement nomElement = new BaseElement(Parser.NOM_NODE_NAME);

		writer.writeOpen(nomElement);
		writer.write(nom);
		writer.writeClose(nomElement);

		nomElement.clearContent();
	}

	private void ecrireClassement(XMLWriter writer, Classement classement) throws IOException {
		BaseElement classementElement = new BaseElement(Parser.TYPE_NODE_NAME);

		writer.writeOpen(classementElement);
		writer.write(classement.toString());
		writer.writeClose(classementElement);

		classementElement.clearContent();
	}

	private void ecrireTroncon(XMLWriter writer, Troncon troncon) throws IOException {
		BaseElement tronconElement = new BaseElement(Parser.TRONCON_NODE_NAME);

		writer.writeOpen(tronconElement);

		ecrireVille1(writer, troncon.getVille1());
		ecrireVille2(writer, troncon.getVille2());
		ecrireVitesse(writer, Integer.toString(troncon.getVitesse()));

		for (AtoutTouristiqueTroncon atout : troncon.getAtoutsTouristiques()) {
			ecrireATT(writer, atout);
		}

		ecrireRadar(writer, troncon.getCaracteristique(Radar.getInstance().intitule()));
		ecrirePeage(writer, troncon.getCaracteristique(Peage.getInstance().intitule()));
		ecrireLongueur(writer, Integer.toString(troncon.getLongueur()));

		writer.writeClose(tronconElement);

		tronconElement.clearContent();
	}

	private void ecrireVille1(XMLWriter writer, Ville ville1) throws IOException {
		BaseElement villeElement = new BaseElement(Parser.VILLE1_NODE_NAME);

		writer.writeOpen(villeElement);
		writer.write(ville1.getNom());
		writer.writeClose(villeElement);

		villeElement.clearContent();
	}

	private void ecrireVille2(XMLWriter writer, Ville ville2) throws IOException {
		BaseElement villeElement = new BaseElement(Parser.VILLE2_NODE_NAME);

		writer.writeOpen(villeElement);
		writer.write(ville2.getNom());
		writer.writeClose(villeElement);

		villeElement.clearContent();
	}

	private void ecrireVitesse(XMLWriter writer, String vitesse) throws IOException {
		BaseElement vitesseElement = new BaseElement(Parser.VITESSE_NODE_NAME);

		writer.writeOpen(vitesseElement);
		writer.write(vitesse);
		writer.writeClose(vitesseElement);

		vitesseElement.clearContent();
	}

	private void ecrireATT(XMLWriter writer, AtoutTouristiqueTroncon atout) throws IOException {
		BaseElement atoutElement = new BaseElement(Parser.TOURIST_NODE_NAME);

		writer.writeOpen(atoutElement);
		writer.write((atout != null) ? Parser.IND_POSITIVE : Parser.IND_NEGATIVE);
		writer.writeClose(atoutElement);

		atoutElement.clearContent();
	}

	private void ecrireRadar(XMLWriter writer, Caracteristique radar) throws IOException {
		BaseElement radarElement = new BaseElement(Parser.RADAR_NODE_NAME);

		writer.writeOpen(radarElement);
		writer.write((radar != null) ? Parser.IND_POSITIVE : Parser.IND_NEGATIVE);
		writer.writeClose(radarElement);

		radarElement.clearContent();
	}

	private void ecrirePeage(XMLWriter writer, Caracteristique peage) throws IOException {
		BaseElement peageElement = new BaseElement(Parser.PAYANT_NODE_NAME);

		writer.writeOpen(peageElement);
		writer.write((peage != null) ? Parser.IND_POSITIVE : Parser.IND_NEGATIVE);
		writer.writeClose(peageElement);

		peageElement.clearContent();
	}

	private void ecrireLongueur(XMLWriter writer, String longueur) throws IOException {
		BaseElement longueurElement = new BaseElement(Parser.LONGUEUR_NODE_NAME);

		writer.writeOpen(longueurElement);
		writer.write(longueur);
		writer.writeClose(longueurElement);

		longueurElement.clearContent();
	}
}
